package com.ecreditpal.audio.platform.ali;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriber;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberListener;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberResponse;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.ecreditpal.audio.AsrCallback;
import com.ecreditpal.audio.AsrRunner;
import com.ecreditpal.audio.model.AudioSession;
import com.ecreditpal.audio.platform.Config;
import lombok.extern.slf4j.Slf4j;


import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

/**
 * @author lifeng
 * @version 1.0 on 2018/7/8.
 */
@Slf4j
public class AliyunAsr extends AsrRunner{
    NlsClient client;
    private volatile Long tokenExpireTime;

    private Config config;

    private static final Object lock = new Object();

    @Override
    public void init(Config config) {
        this.config = config;
        JSONObject jsonObject = getToken(config);
        String token  =  jsonObject.getString("Id");

        this.tokenExpireTime = jsonObject.getLongValue("ExpireTime");
        client = new NlsClient(token);
    }

    public NlsClient getClient() {
        long now = System.currentTimeMillis();
        if (now + TimeUnit.MILLISECONDS.toHours(2) > tokenExpireTime) {
            synchronized (lock) {
                JSONObject jsonObject = getToken(config);
                String token  =  jsonObject.getString("Id");
                this.tokenExpireTime = jsonObject.getLongValue("ExpireTime");
                this.client = new NlsClient(token);
            }
        }
        return this.client;
    }




    private static SpeechTranscriberListener getTranscriberListener(AsrCallback asrCallback) {
        SpeechTranscriberListener listener = new SpeechTranscriberListener() {
            private StringBuilder text = new StringBuilder();
            // 识别出中间结果.服务端识别出一个字或词时会返回此消息.仅当setEnableIntermediateResult(true)时,才会有此类消息返回
            @Override
            public void onTranscriptionResultChange(SpeechTranscriberResponse response) {
                System.out.println("name: " + response.getName() +
                        // 状态码 20000000 表示正常识别
                        ", status: " + response.getStatus() +
                        // 句子编号，从1开始递增
                        ", index: " + response.getTransSentenceIndex() +
                        // 当前的识别结果
                        ", result: " + response.getTransSentenceText() +
                        // 当前已处理的音频时长，单位是毫秒
                        ", time: " + response.getTransSentenceTime());
            }
            // 识别出一句话.服务端会智能断句,当识别到一句话结束时会返回此消息
            @Override
            public void onSentenceEnd(SpeechTranscriberResponse response) {
                System.out.println("name: " + response.getName() +
                        // 状态码 20000000 表示正常识别
                        ", status: " + response.getStatus() +
                        // 句子编号，从1开始递增
                        ", index: " + response.getTransSentenceIndex() +
                        // 当前的识别结果
                        ", result: " + response.getTransSentenceText() +
                        // 当前已处理的音频时长，单位是毫秒
                        ", time: " + response.getTransSentenceTime());
                text.append(response.getTransSentenceText()).append(",");
            }
            // 识别完毕
            @Override
            public void onTranscriptionComplete(SpeechTranscriberResponse response) {
                log.info("识别完毕,name:{},status:{},content,{}",response.getName(),response.getStatus(),text.toString());

                asrCallback.sendMessage(text.toString());
            }
        };
        return listener;
    }
    public void process(byte[] data, AsrCallback asrCallback) {
        SpeechTranscriber transcriber = null;
        try {
            // Step1 创建实例,建立连接
            transcriber = new SpeechTranscriber(getClient(), getTranscriberListener(asrCallback));
            transcriber.setAppKey(config.getAppKey());
            // 输入音频编码方式
            transcriber.setFormat(InputFormatEnum.PCM);
            // 输入音频采样率
            transcriber.setSampleRate(config.getByteRate().equals(8000)?SampleRateEnum.SAMPLE_RATE_8K:SampleRateEnum.SAMPLE_RATE_16K);
            // 是否返回中间识别结果
            transcriber.setEnableIntermediateResult(false);
            // 是否生成并返回标点符号
            transcriber.setEnablePunctuation(true);
            // 是否将返回结果规整化,比如将一百返回为100
            transcriber.setEnableITN(true);
            // Step2 此方法将以上参数设置序列化为json发送给服务端,并等待服务端确认
            transcriber.start();
            // Step3 语音数据来自声音文件用此方法,控制发送速率;若语音来自实时录音,不需控制发送速率直接调用 recognizer.sent(ins)即可

            InputStream is = new ByteArrayInputStream(data);
            transcriber.send(is,6400,200);
            // Step4 通知服务端语音数据发送完毕,等待服务端处理完成
            transcriber.stop();
        } catch (Exception e) {
            log.error("",e);
        }
        finally {
            // Step5 关闭连接
            if (null != transcriber) {
                transcriber.close();
            }
        }
    }
    public void shutdown() {
        client.shutdown();
    }

    public JSONObject getToken(Config config) {
        // 创建DefaultAcsClient实例并初始化
        DefaultProfile profile = DefaultProfile.getProfile(
                "cn-shanghai",          // 您的地域ID
                config.getAppId(),      // 您的Access Key ID
                config.getAppSecret()); // 您的Access Key Secret
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        request.setDomain("nls-meta.cn-shanghai.aliyuncs.com");
        request.setVersion("2018-05-18");
        request.setUriPattern("/pop/2018-05-18/tokens");
        request.setMethod(MethodType.POST);
        CommonResponse response = null;
        try {
            response = client.getCommonResponse(request);
            if (response.getHttpStatus() == 200) {
                JSONObject result = JSON.parseObject(response.getData());
//            String token = result.getJSONObject("Token").getString("Id");
//            long expireTime = result.getJSONObject("Token").getLongValue("ExpireTime");

                return result.getJSONObject("Token");
            }
        } catch (ClientException e) {
            log.error("",e);
        }
        return null;
    }

    public static void main(String[] args) throws IOException {
        AliyunAsr aliyunAsr = new AliyunAsr();
        Config config = new Config();
        config.setAppKey("7h1HksRr87hEMq3f");
        config.setAppId("LTAIL1hJ2qwzVnii");
        config.setAppSecret("IIhD7inF7iDpupLpHEM22Xuett27aU");

        aliyunAsr.init(config);

        InputStream is = new FileInputStream("/Users/lifeng/Desktop/pp3.wav");
        byte[] b = new byte[is.available()];

        is.read(b);
        aliyunAsr.process(b,null);

    }
}
